"""
Case Type   : 故障&可靠性测试
Case Name   : 主备节点时区不一致时dump数据，主备节点时区一致时resotre数据
Create At   : 2020/11/25
Owner       : @zou_jialiang0505328126
Description :
    1.修改主点时区，跟备节点不一致
    2.使用gs_dump导出数据
    3.修改主节点时区跟备节点一致
    4.使用gs_restore恢复数据
    5.检查数据一致性
    6.启动TPCC
    7.检查数据一致性
Expect      :
    1.设置成功
    2.导出成功
    3.设置成功
    4.恢复成功
    5.数据一致
    6.执行tpcc成功
    7.数据一致
History     :
    modified: 2020/12/15  modified by @wan005,修改恢复数据库为新创建数据库，防止恢复失败导致后续用例失败
    modified: 2021/01/08  modified by @wan005,物化视图不支持compression等参数，修改断言适配1.1.0版本
"""

import os
import unittest
import sys
import time
from yat.test import macro
from yat.test import Node

sys.path.append(sys.path[0] + "/../")
from testcase.utils.CommonSH import *
from testcase.utils.Common import Common
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger

## 默认  /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai
New_York_Local = '/usr/share/zoneinfo/America/New_York'
LN_SF_CMD = 'ln -sf {zone} /etc/localtime'


class Basebackup(unittest.TestCase):
    commonshpri = CommonSH('PrimaryDbUser')
    commonshsta = CommonSH('Standby1DbUser')
    commonshsta2 = CommonSH('Standby2DbUser')
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info('------------Opengauss_Reliability_Tools_Restore_Case033.py 开始执行------------')
        self.dbPrimaryDbUser = Node(node='PrimaryDbUser')
        self.dbStandby1DbUser = Node(node='Standby1DbUser')
        self.dbStandby2DbUser = Node(node='Standby2DbUser')
        self.dbStandby1Root = Node(node='Standby1Root')
        self.dbPrimaryRootNode = Node(node='PrimaryRoot')
        self.Constant = Constant()
        self.common = Common('PrimaryRoot')
        self.restore_file = os.path.join(macro.DB_BACKUP_PATH, 'dump_backup', 'tools_restore_case001.tar')
        self.sql_path = os.path.join(macro.DB_BACKUP_PATH, 'testscript')
        self.currentLocalZoneStr = self.dbStandby1Root.sh('ls -l /etc/localtime').result()

        self.log.info('-------------------创建备份路径-----------------------------------')
        shell_cmd = f'rm -rf {os.path.dirname(self.restore_file)}; mkdir {os.path.dirname(self.restore_file)}'
        self.log.info(shell_cmd)
        result = self.dbPrimaryDbUser.sh(shell_cmd).result()
        self.log.info(result)

        self.log.info('-----------------------生成预设数据-----------------------')
        result = self.common.scp_file(self.dbPrimaryDbUser, 'restore_data.sql', self.sql_path)
        self.log.info(result)
        sql_file_cmd = f'''
                            source {macro.DB_ENV_PATH};    
                            gsql -d {self.dbPrimaryDbUser.db_name} -p {self.dbPrimaryDbUser.db_port}  -f {os.path.join(
            self.sql_path, 'restore_data.sql')}  '''
        self.log.info(sql_file_cmd)
        sql_bx_msg = self.dbPrimaryDbUser.sh(sql_file_cmd).result()
        self.log.info(sql_bx_msg)
        self.assertNotIn('ERROR', sql_bx_msg)

        self.log.info('--------------------获取还原前数据库已有表------------------------')
        self.table_list = self.commonshpri.executDbSql(r'\d')
        self.log.info(self.table_list)

        self.dbname = 'dbsys_restore_db'
        self.log.info("---------------------创建数据库--------------------")
        result = self.commonshpri.executDbSql(f'drop database if exists {self.dbname};create database {self.dbname};')
        self.log.info(result)
        self.assertIn(self.Constant.CREATE_DATABASE_SUCCESS_MSG, result)

    def test_basebackup(self):
        self.log.info("------------------修改 postgresql.conf----------------------")
        cmd = '''\
                    cp {dbIns}/postgresql.conf {dbIns}/postgresql.conf.timezone;
                    echo "timezone=America/New_York" >> {dbIns}/postgresql.conf
                '''.format(dbIns=macro.DB_INSTANCE_PATH)
        self.dbPrimaryDbUser.sh(cmd)

        self.log.info("------------------重载配置文件---------------------")
        result = self.commonshpri.reloadDbConfig()
        self.log.info(result)
        self.assertIn(self.Constant.RELOAD_SUCCESS_MSG, result)

        self.log.info("-----------设置主节点时区为纽约--------------------")
        zonecmd = LN_SF_CMD.format(zone=New_York_Local)
        self.dbPrimaryRootNode.sh(zonecmd)
        result = self.dbPrimaryRootNode.sh('ls -l /etc/localtime').result()
        self.log.info(result)
        self.assertIn(New_York_Local, result)

        self.log.info('--------------------导出数据----------------------------')
        result = self.commonshpri.dumpFile(filename=self.restore_file,get_detail=False)
        self.log.info(result)
        self.assertTrue(result)

        time.sleep(3)

        self.log.info("-----------恢复 postgresql.conf--------------------")
        cmd = f'mv {macro.DB_INSTANCE_PATH}/postgresql.conf.timezone {macro.DB_INSTANCE_PATH}/postgresql.conf; '
        self.dbPrimaryDbUser.sh(cmd)

        self.log.info("------------------重载配置文件---------------------")
        result = self.commonshpri.reloadDbConfig()
        self.log.info(result)
        self.assertIn(self.Constant.RELOAD_SUCCESS_MSG, result)

        self.log.info("----------还原主节点时区--------------------")
        recoverTimezone = self.currentLocalZoneStr.split('->')[1]
        zonecmd = LN_SF_CMD.format(zone=recoverTimezone)
        self.log.info('recover: ' + zonecmd)
        self.dbPrimaryRootNode.sh(zonecmd)
        result = self.dbPrimaryRootNode.sh('ls -l /etc/localtime').result()
        self.log.info(result)
        self.assertIn(self.currentLocalZoneStr.split('->')[1], result)
        time.sleep(10)

        self.log.info('-------------------恢复数据-----------------------------------')
        result = self.commonshpri.restoreFile(self.restore_file,' ', True, self.dbname)
        self.assertIn(self.Constant.RESTORE_SUCCESS_MSG, result)

        self.log.info('-------------------检查主备是否同步-------------------')
        result = self.commonshsta.check_data_consistency()
        self.assertTrue(result)
        result = self.commonshsta2.check_data_consistency()
        self.assertTrue(result)

        self.log.info('--------------------检查数据一致性---------------------')
        nodes_tuple = (self.dbPrimaryDbUser, self.dbStandby1DbUser, self.dbStandby2DbUser)
        flag = self.common.check_data_sample_by_all(r'\d', *nodes_tuple)
        self.assertTrue(flag)

        table_dict = self.common.format_sql_result(self.commonshpri.executDbSql(r'\d', dbname=self.dbname))
        table_name = table_dict.get('Name')
        for name in table_name:
            select_sql = f'select count(*) from {name};'
            flag = self.common.check_data_sample_by_all(select_sql, *nodes_tuple)
            self.assertTrue(flag)

        self.log.info('------------------启动TPCC----------------------------')
        result = self.common.startTPCC(self.dbPrimaryRootNode, macro.TPCC_PATH)
        self.log.info(result)
        self.assertIn(self.Constant.TPCC_SUCCESS_MSG, result)

        self.log.info('-------------------检查主备是否同步-------------------')
        result = self.commonshsta.check_data_consistency()
        self.assertTrue(result)
        result = self.commonshsta2.check_data_consistency()
        self.assertTrue(result)

        self.log.info('--------------------检查数据一致性---------------------')
        nodes_tuple = (self.dbPrimaryDbUser, self.dbStandby1DbUser, self.dbStandby2DbUser)
        flag = self.common.check_data_sample_by_all(r'\d', *nodes_tuple)
        self.assertTrue(flag)

        table_dict = self.common.format_sql_result(self.commonshpri.executDbSql(r'\d'))
        table_name = table_dict.get('Name')
        for name in table_name:
            select_sql = f'select count(*) from {name};'
            flag = self.common.check_data_sample_by_all(select_sql, *nodes_tuple)
            self.assertTrue(flag)

    def tearDown(self):
        self.log.info('-------------------------环境清理------------------------')
        self.log.info('--------------------------删除备份文件------------------')
        shell_cmd = f'rm -rf {os.path.dirname(self.restore_file)}'
        self.log.info(shell_cmd)
        result = self.dbPrimaryDbUser.sh(shell_cmd).result()
        self.log.info(result)

        self.log.info('--------------------------删除预设数据---------------------')
        result = self.common.scp_file(self.dbPrimaryDbUser, 'clear_restore_data.sql', self.sql_path)
        self.log.info(result)
        sql_file_cmd = f'''
                                                       source {macro.DB_ENV_PATH};
                                                       gsql -d {self.dbPrimaryDbUser.db_name} -p {self.dbPrimaryDbUser.db_port}  -f {os.path.join(
            self.sql_path, 'clear_restore_data.sql')}
                        '''
        self.log.info(sql_file_cmd)
        sql_bx_msg = self.dbPrimaryDbUser.sh(sql_file_cmd).result()
        self.log.info(sql_bx_msg)

        self.log.info('----------------------删除执行脚本路径----------------------------')
        shell_cmd = f'rm -rf {self.sql_path}'
        self.log.info(shell_cmd)
        result = self.dbPrimaryDbUser.sh(shell_cmd).result()
        self.log.info(result)

        self.log.info("-----------恢复系统时区--------------------")
        cmd = f'mv {macro.DB_INSTANCE_PATH}/postgresql.conf.timezone {macro.DB_INSTANCE_PATH}/postgresql.conf; '
        self.dbPrimaryDbUser.sh(cmd)
        result = self.commonshpri.reloadDbConfig()
        self.log.info(result)

        result = self.dbPrimaryRootNode.sh('ls -l /etc/localtime').result()
        self.log.info(result)
        if self.currentLocalZoneStr.split('->')[1] not in result:
            recoverTimezone = self.currentLocalZoneStr.split('->')[1]
            zonecmd = LN_SF_CMD.format(zone=recoverTimezone)
            self.log.info('recover: ' + zonecmd)
            self.dbPrimaryRootNode.sh(zonecmd)
            result = self.dbPrimaryRootNode.sh('ls -l /etc/localtime').result()
            self.log.info(result)

        self.log.info("---------------------drop database--------------------")
        result = self.commonshpri.executDbSql(f'drop database {self.dbname};')
        self.log.info(result)
        self.log.info('----------Opengauss_Reliability_Tools_Restore_Case033.py 执行结束-----------------------')
